home *** CD-ROM | disk | FTP | other *** search
- /* MacStarter is a shell for simple Macintosh applications shell written in
- THINK C, with some small use of its object-oriented features.
- This file is the place to start when you want to write a new application
- with MacStarter. The whole system is described in a README file that
- should be in the same folder with this file. There should also be
- sample applicationProc files (kaleidoSketch.c, pentominos.c and
- simpleScroll.c). Finally, the file uncommentedProcs.c is a copy
- of this file without any comments, in case you would rather use that
- as a starting point.
- To write an application, you need to fill in or modify at least some
- of the functions in this file. (You should start by copying and renaming
- the file.) The places in the file where you might need to do some work
- are all commented with comments beginning with //. Most of them are
- also in the "mark menu" that you see when you hold down the command key
- and press the mouse in the title bar of this window.
- */
-
-
- #include "globals-MacStarter.h"
-
- long gEventWaitTime = 1000000; // This is used by function WaitNextEvent in the
- // main program as the maximum acceptable time for the program to
- // be "put to sleep" while waiting for the next event. If your
- // program has an "ApplicationIdle" function, you will need to
- // change this value. See the comment on that function. Otherwise,
- // you can ignore gEventWaitTime.
-
-
- MenuHandle editMenu, fileMenu; // These variables are defined to provide a
- // way to refer to the file and edit menus in function UpdataMenus.
- // If you add other menus, you will need to define MenuHandles for
- // them.
-
-
- void InitApplication(void); // This is a list of the functions
- void UpdateMenus(void); // defined in this file. (I have to
- void DoEditMenu(int itemNum); // declare functions before
- void DoFileMenu(int itemNum, int* done); // defining them because I turned
- void DoOtherMenu(int menuID, int itemNum); // on the "Require Prototypes"
- void ApplicationIdle(void); // option in the Language Settings
- void CleanUpApplication(void); // panel of the Options dialog.)
- void AboutBox(void);
- void DoNewCommand(void);
-
-
-
- /*********************** Window definition **********************************/
-
-
- class myWindow : public xWindow {
-
- // The class xWindow is defined in globals-MacStarter.c. It provides the
- // basic functionality of Macintosh windows. You define the behaviour of
- // actual windows in your program by defining the subclass myWindow of
- // class xWindow. To do this, you just have to say how your window
- // responds to certain events, by filling in the definitions of the
- // functions that are called in response to those events. The list
- // of functions that you might have to change is given in this
- // "subclass declaration" for myWindow. The actual functions follow.
- // See the individual functions for more information.
-
- // You will almost certainly need to add some information to this
- // definition of myWindow. You should insert here the
- // declarations of any variables you need to hold data relevant
- // to the contents of the window. These variables should be defined
- // HERE, not as global variables, since each window needs its own
- // version of the variables. You can also add new functions to the
- // following list of functions. (NOTE: You can certainly define
- // additional window classes, if your program needs windows with a
- // variety of behaviours.)
-
- public:
- virtual void OpenInRect(Str255 title, int left, int top, int right, int bottom);
- virtual short Close(void);
-
- protected: // (Note: You will never actually CALL these functions directly;
- // just define what they do.)
- virtual void SetDefaults(void);
- virtual void doKey(char ch);
- virtual void doContentClick(Point localPt);
- virtual void adjustToNewSize(void);
- virtual void doRedraw(Rect* badRect);
- virtual void doHScroll(int dh);
- virtual void doVScroll(int dv);
- virtual void doActivate(int active);
-
- };
-
-
- // Function SetDefaults is called automatically when a new window is opened,
- // BEFORE the actual window is created. It sets up the appearance of the
- // window and initializes variables associated with the window. This function
- // should always START by calling inherited::SetDefaults, which sets up the
- // default appearance and behaviour. THEN, you can make any changes you
- // want.
- // The inherited function gives default values to the variables
- // features, topScrollOffset, bottomScrollOffset, leftScrollOffset,
- // rightScrollOffset, minH, minV, maxH, maxV, hLinesPerPage and
- // vLinesPerPage. The most important of these is FEATURES, which
- // determines whether or not the window has a go-away box, a zoom box,
- // a grow box, a horizontal scroll bar, and a vertical scroll bar. Its
- // default value is hasGoAway + hasZoom + hasGrow + hasHScroll + hasVScroll,
- // which will produce a window with all possible features. If you want
- // only a subset of features, you should set the value of features
- // appropriately. For example, features = hasGoAway will produce a
- // non-resizable, unscrollable window with a go-away box in the upper left
- // corner that the user can click on to close the window.
- // You will probably not need to worry about the other varaibles,
- // but, for the record: minH, minV, maxH and maxV determine how big
- // and how small the user can make the window by dragging the grow box in
- // the lower right corner of the window. The defaults allow very large and
- // very small values. The range of allowable horizontal sizes for the window is
- // from minH to maxH, and for vertical sizes is minV to maxV. You might well
- // want to change minH and minV to prevent really small windows. You
- // can set minH to have the same value as maxH. In that case, the window
- // can only be resized vertically. (But be sure that the window is first
- // opened at the correct size!) If your window has a maximum size, it should
- // not have a zoom box, since zooming will not respect the maximum size.
- // When a user clicks in the gray region of a scroll bar, the window
- // should scroll by a greater amount than when the user clicks in an
- // arrow. The variables hLinesPerPage and vLinesPerPage control this
- // behaviour. By definition, a click in the gray area of the horizontal scroll
- // bar is equivalent to hLinesPerPage clicks on one of the horizontal scroll's
- // arrows. Similarly for vLinesPerPage. Usually, the correct values
- // for these variables depend on the size of the window, so they would
- // ordinarily be reset in function adjustToNewSize().
- // By default, the window's scroll bars will extend all the way across,
- // or up and down, the window. Sometimes, you might want to leave some
- // space at one end or another of a scroll bar. If so, you can set
- // the value of one of the variables topScrollOffset, bottomScrollOffset,
- // leftScrollOffset or rightScrollOffset. These work in what should be
- // a obvious way.
-
- void myWindow::SetDefaults(void) {
- inherited::SetDefaults();
- // Make changes to defaults. You also can initialize the window's data.
- // Most likely change is erase some of the items on the right of:
- // features = hasHScroll + hasVScroll + hasGoAway + hasZoom + hasGrow;
- }
-
-
- // Function OpenInRect is called whenever a window needs to be opened. It should
- // start by calling the default inherited::OpenInRect, which actually opens
- // the window (including calling SetDefaults in turn). After this, you can
- // do any further initialization your window might need. (Most initialization
- // can be done in SetDefaults, but when SetDefaults is called, the actual
- // window doesn't exist yet. In some cases, such as installing a TEdit or
- // a Control, you need the actual window. These things can be done in the
- // function below, after the call to inherited::OpenInRect. The variable
- // that points to the Mac window data structure is called theWindow.)
-
- void myWindow::OpenInRect(Str255 title, int left, int top, int right, int bottom) {
- inherited::OpenInRect(title,left,top,right,bottom);
- // insert any additional initialization of window data here.
- }
-
-
- // Function myWindow::Close is called when the window is closing (for example,
- // when the user clicks in its GoAway box). If you have any dynamically allocated
- // variables in the window, this is the place to delete their storage.
- // It is ESSENTIAL that the call to inherited::Close be the LAST thing in
- // this function. (This function is declared to return a short in case you
- // want a Close function that can "refuse to close" by returning a value
- // of zero. Typically, you might ask if the user wants to save the window
- // contents before closing, and you might provide a CANCEL option that
- // should abort the closing. If the window is closing because the user
- // chose QUIT from the file menu, you will need to know that the user
- // decided to cancel. You could then call the close function like this:
- // if ( win->Close() ) ... )
-
- short myWindow::Close(void) {
- // Clean-up before closing window.
- inherited::Close(); // You can't refer to any window data after this call !
- return 1; // not used in the existing program
- }
-
-
- // Function doKey is called when the user types any character. The character
- // typed is passed as the parameter ch. If you want to get at the actual
- // event record that generated this function call, you can find it in the
- // global variable gEvent. You can, for example, check whether the user
- // was holding down the option key by checking:
- // if ( gEvent.modifiers & optionKey ) ... Note that command key events
- // are NOT sent to this function. They are automatically intercepted and
- // changed into menu events.
- // NOTE: Before this function is called, the "graphics port" is set to
- // this window. That just means that ANY drawing you do in this function
- // will apply to this window.
-
- void myWindow::doKey(char ch) {
- // Handle key-click
- }
-
-
- // Function doContentClick is called when your program needs to respond to
- // a user clicking the mouse on this widow. (Clicks on scroll bars, grow
- // boxes, etc, are handled automatically and are NOT sent to this function.
- // Also, when the user clicks on an inactive window, that click is handled
- // by activating the window and is NOT sent to this function.) The coordinates
- // of the point where the user clicked are sent in the parameter localPt.
- // These coordinates are in the window's local coordinates (in which the
- // top, left corner is (0,0) unless you have changed them). You can get
- // full information about the mouse-down event from the global variable
- // gEvent. For example, "if (gEvent.modifiers & cmdKey)..." will test
- // whether the user was holding down the command key when the mouse was clicked.
- // In addition, the global variable gClickCount can be used to determine
- // whether this is a double click; this variable is set to 1 for a single
- // click, to 2 for the second click of a double click, to 3 for the third
- // click of a triple click, etc. For a double click, for example, this function
- // gets BOTH clicks in succession, with gClickCount set to 1 the first
- // time and to 2 the second time. (Also NOTE: The Macintosh toolbox function
- // StillDown() will be true as long as the user continues to hold down the
- // mouse key. You might, for example, use a while (StillDown()) loop to
- // follow the mouse or perform some action as long as the user holds down
- // the button.)
- // NOTE: Before this function is called, the "graphics port" is set to
- // this window. That just means that ANY drawing you do in this function
- // will apply to this window.
-
- void myWindow::doContentClick(Point localPt) {
- // Handle a mouse click
- }
-
-
- // Function doRedraw is called when the window, or a portion of it, needs to
- // be redrawn (because the window has been resized or moved from behind
- // another window, for example.) It is also called when the window is
- // first opened (after all the initialization done in SetDefaults and
- // OpenInRect). Note that your window always needs to save enough data
- // to redraw itself (if you want your application to act like a real Mac program).
- // Ordinarily, you will simply redraw the entire contents of the window.
- // However, if your window is very complicated, you might save some time
- // by using the parameter badRect. This is a rectangle that contains the
- // portion of the window that actually needs to be redrawn.
- // If your window uses scroll bars, you will need to know the current
- // settings and maximums on those scroll bars. You can find out by
- // calling the functions GetHVal(), GetVVal(), GetHMax() and GetVMax().
- // (People sometimes have trouble understanding this function. It has to
- // exist because the Mac doesn't actually remember what's in your window.
- // When one window covers another, anything in the bottom window is forgotten
- // When the window is later uncovered, the Mac sticks you with the
- // responsibility of remembering what was there and reconstituting it.
- // So, ordinarily, this function is redoing old work rather than getting
- // new work done. This imposes the great burden on the programmer of
- // remembering what's in each window.)
- // NOTE: Before this function is called, the "graphics port" is set to
- // this window. That just means that ANY drawing you do in this function
- // will apply to this window.
-
- void myWindow::doRedraw(Rect* badRect){
- // redraw current contents of window.
- }
-
-
- // Function adjustToNewSize is called whenever the window changes size because
- // the user drags its grow box or clicks its zoom box. If you need to make
- // any changes to accomodate the new size, do it here. However, DO NOT
- // redraw the window here; function doRedraw() is going to be called
- // automatically after this function to do the actual redrawing.
- // The inherited function simply resizes and moves the scroll bars, if any.
- // After this, you might need to readjust the values, maximums or
- // linesPerPage associated with the scroll bars. The functions SetHVal(),
- // SetVVal(), SetHMax(), SetVMax(), SetHLinesPerPage() and SetVLinesPerPage()
- // can be used to change these settings. If you have TEdits or
- // controls of your own, they will have to be resized and moved. If the
- // stuff drawn in the window needs to be scaled to the new size, you can do
- // it here.
-
- void myWindow::adjustToNewSize(void) {
- inherited::adjustToNewSize();
- // respond to change in window size
- }
-
-
- // Function doHScroll is called when the user changes the position of the
- // horizontal scroll. It will be called repeatedly if the user holds down the
- // mouse button on an arrow or in the gray area of the scroll. The inherited
- // function simply erases the sreen and then calls your DoRedraw() function
- // to redraw the screen contents (presumably reflecting the new position of
- // the scroll). Depending on your application, this might be fine, but it
- // can cause an annoying flicker and can be too time-consuming. If you
- // want to change this, you should ERASE the call to inherited::doHScroll
- // and substitute your own code. (Typically, you will call the Mac
- // Toolbox routine ScrollRect() and then just do the minimal redrawing
- // necessary.) The parameter tells the CHANGE in the value of the horizontal
- // scroll. You can get the actual new value by calling GetHVal().
-
- void myWindow::doHScroll(int dh) {
- inherited::doHScroll(dh); // replace with your own code if you
- // don't like the default behaviour
- }
-
-
- // Function doVScroll is called when the user changes the position of the
- // vertical scroll. Similar comments to those on doHScroll() apply.
-
- void myWindow::doVScroll(int dv) {
- inherited::doVScroll(dv); // replace with your own code if you
- // don't like the default behaviour
- }
-
-
- // Function doActivate is called when your window is deactivated (because
- // the user clicks on another window) or activated (because the user clicks
- // on this window and it is being moved to the front). The inherited
- // function takes care of activating or deactivating the scroll bars. If
- // your window has its own control or TEdit, you can activate or deactivate
- // them here. Otherwise, there is probably nothing that this function
- // needs to do. (In particular, this function does NOT redraw the window.)
- // The parameter "active" is 0 if the window is being deactivated and is
- // non-zero if it is being activated.
-
- void myWindow::doActivate(int active) {
- inherited::doActivate(active);
- // activate/deactivate controls, TEdits, etc. (if any)
- }
-
-
- /****************************************************************************/
-
-
- // Function InitApplication is called when the application first starts up.
- // It should be used to initialize any global variables that require
- // initialization. Here, it is also used to open the first window
- // of the program.
-
- void InitApplication(void) {
- MenuHandle appleMenu;
- fileMenu = GetMHandle(2); // get handles to the menus, for use in UpdateMenus
- editMenu = GetMHandle(3);
- appleMenu = GetMHandle(1); // Note that your program is not responsible for
- // managing the apple menu, except to set the
- // program name in the first line of the
- // menu, as is done in the next line.
- SetItem(appleMenu,1,"\pAbout Generic...");
- DoNewCommand(); // opens a window.
- }
-
-
- // Function UpdateMenus() is called just before any user action directed at the
- // menu bar is processed. That is, it is called when the user clicks in
- // the menu bar (but before the user sees any menus), or when the user
- // command-presses a keyboard key (but before that command is looked up
- // in the menus). The purpose of this function is to enable and
- // disable commands as appropriate. A command that is "disabled" is
- // grayed out in the menu and is unavaialble to the user. For example,
- // if there is no window open, then the Close Window command should
- // certainly be disabled. The function UpdateMenus should set the
- // enable/disable status of any menu item whose status can change.
- // (In the existing program's file menu, for example, the New and
- // Quit commands are always enabled. The Close command is enabled and
- // disabled as appropriate by this function.)
- // The Edit menu is a special case. This menu is supposed to be
- // available, with all its standard commands enabled, if the front window
- // on the screen belongs to a desk accessory rather than to your program.
- // This is handled by the first few lines of the function below, which
- // you should not change. You should also not insert new items into
- // the edit menu, except at the end, after the standard items.
-
- void UpdateMenus(void) {
-
- short i;
- WindowPtr win; // pointer to macintosh window data structure
- xWindow *xwin; // pointer to xWindow data structure
-
- win = FrontWindow(); // this is the front window on the screen
-
- if ( win && ((WindowPeek)win)->windowKind < 0 ) { // Desk accessory window
- EnableItem(editMenu,1); // Do not change this section.
- for (i=3; i<7; i++) // This has nothing to do with
- EnableItem(editMenu,i); // your program
- }
- else { // enable/disable edit item menus as relevant to your program
- DisableItem(editMenu,1);
- for (i=3; i<7; i++) // Here, I just disable them all
- DisableItem(editMenu,i);
- }
-
- if (win && xWindow::Window2XWindow(win,&xwin)) { //if front window is mine...
- EnableItem(fileMenu,2); // enable Close command
- }
- else {
- DisableItem(fileMenu,2); // disable Close command
- }
- }
-
-
- // Function DoEditMenu is called if the user selects a command from the
- // Edit menu. (By default, these commands are disabled, so this function
- // won't be called unless you enable them in function UpdateMenus().)
- // The parameter gives the item number of the command, counting from the
- // top of the menu.
-
- void DoEditMenu(int itemNum) {
- // handle command from edit menu
- }
-
-
- // Function DoFileMenu() is called if the user selects a command from the
- // File menu. The parameter itemNum gives the number of the command counting
- // down from the top of the menu. NOTE that if you insert items into the
- // menu, the command numbers for the existing commands will change, and these
- // changes will have to be reflected in the if statements in this function.
- // The parameter "done" should be set to 1 if the user chooses QUIT from the
- // file menu; however, you have the possibility of ABORTING this command
- // simply by not setting this value. (For example, you might as the user
- // if she wants to save her data before quitting and she might click on the
- // cancel button in the dialog box.)
-
- void DoFileMenu(int itemNum, int* done) {
- xWindow *win;
- // Handle file menu commands:
- if (itemNum == 4)
- *done = 1;
- else if (itemNum == 1)
- DoNewCommand();
- else if (itemNum == 2 && xWindow::Window2XWindow(FrontWindow(),&win))
- win->Close();
- }
-
-
- // If you have added other menus besides the Apple, File and Edit menus,
- // this function will be called when the user chooses a command from
- // such a menu. The parameters tell you the menu and the number of the
- // item in the menu. Note that the first parameter is the menuID,
- // NOT the position of the menu in the menu bar. (If the menu comes out
- // of a resource file, the menuID is the resource number; if you create it
- // "on the fly", you set the menuID when you create it.)
-
- void DoOtherMenu(int menuID, int itemNum) {
- // handle command (from menu other than apple, file or edit menu)
- }
-
-
- // Function ApplicationIdle is called periodically while your program is
- // running. Specifically, it is called each time an "event" is generated
- // by the user or by the operating system. User events include mouse and
- // key clicks. Operating system events are things like window-activation
- // events. In addition, if no other event occurs, the operating system
- // can send a "null" event. The purpose of such an event is exactly to
- // make sure that a function like ApplicationIdle gets called sufficiently
- // often. The frequency of null events is determined by the global
- // varialble gEventWaitTime. If you put anything into this function,
- // you should change the value of this variable at the top of this
- // file. gEventWaitTime is measured in 1/60-ths of a second. It represents
- // the maximum time that you would like between calls to ApplicationIdle.
- // (It is not a guaranteed that the operating system will always be able to
- // meet this deadline; it depends on what else is going on in the system.)
- // One common use of ApplicationIdle is to set the cursor style to reflect
- // the part of the screen that the mouse is currently over. If you do this,
- // a value of gEventWaitTime of about 3 seems to work well.
- // Another use is to allow the null events to "drive" a long computation
- // or an animation. If you just go ahead and do an animation, say, with a
- // long for loop, there will be no way for the user to interrupt it. It is
- // better to use ApplicationIdle to do just one frame of an animation or
- // one small piece of a computation. Of course, this is much more difficult--
- // you need to keep track of what you are doing in global variables or
- // window data variables. Anyway, if you do do this, you should set
- // gEventWaitTime to 0. This just asks the operating system to spend
- // as little time as possible away from your program.
- // If your program uses a TEdit (This is a standard Mac text edit box),
- // Then you should call TEIdle in this function and set gEventwaitTime
- // to a value no greater than about 10.
- // The reason for not automatically setting gEventWaitTime to a small
- // value is that the operating system can give time to other programs
- // running in the background if there is nothing for your program to do.
-
- void ApplicationIdle(void) {
- // Perform any periodic task required by your program
- }
-
-
- // Function CleanUpApplication is called just before the program ends normally.
- // You will probably have nothing to do here, especially since there is
- // no way to abort the program termination, but, just in case...
-
- void CleanUpApplication(void) {
- }
-
-
- // Function AboutBox is called when the user chooses the first item in the
- // Apple menu, usually a command of the form "About <program-name>...".
- // It should display information about your program. This default
- // version simply displays a box that has four fill-in-the-blank areas
- // that are set by the call to ParamText(). You can just make changes
- // to this. However, if you happen to use this shell to write a serious
- // program, you will want to do something different. For one thing, this
- // method is totally insecure. Since it just uses one of the resources in
- // the resource file MacStarter.π.rsrc, anyone who wanted to steal credit
- // for your program could do so by editing its resource fork with ResEdit.
- // (It would be better to open a window and draw into it directly.)
- // Note: The \r's in the third line here represent line breaks. There
- // is room for three fairly short lines in this field, which is meant for
- // your address (although, of course, you can use it for whatever you want).
-
- void AboutBox(void) {
- // Set up program name, author name, address, short program description.
- ParamText( "\pGeneric Application",
- "\pDavid Eck",
- "\pHobart and William Smith College\rGeneva, NY 14456\rE-mail: eck@hws.bitnet",
- "\pThis program can be used as a shell for creating Macintosh Applications.");
- Alert(128,0L);
- }
-
-
- // Function DoNewCommand is called from DoFileMenu above when the user chooses
- // the New command from the file menu. In this sample program, it is also
- // called when the program is first started up. It simply creates
- // and opens a window. Here, win->Open(title) will open a window that is
- // about 3/4 the size of the screen in each dimension. Each successive
- // window will be slightly offset from the previous one. You could also
- // open the window with win->OpenFullScreen(title), which will open a window
- // that fills the entire screen. Or, win->OpenInRect(title,L,t,r,b) will
- // open a window in a specified rectangle. In this case, the window extends
- // from L to r horizontally and from t to b vertically. L, t, r and b are
- // measured in screen coordinates, in which the top left corner of the
- // screen is (0,0). (Actually, L, t, r, and b specify the position of the
- // inside of the window only, not including the title bar or a 1-pixel border
- // around the window.)
-
- void DoNewCommand(void) {
- myWindow *win;
- win = new myWindow; // (this create window storage space before opening it)
- win->Open("\pSample Window"); // need a better window title!
- }